package ddz.logic.game;

import com.kaka.notice.Command;
import com.kaka.notice.Message;
import com.kaka.notice.annotation.Handler;
import com.kaka.util.MathUtils;
import com.kaka.util.StringUtils;
import com.kaka.util.Tool;
import ddz.constants.Crypto;
import ddz.constants.OpCode;
import ddz.core.*;
import ddz.core.dealer.Dealer;
import ddz.core.dealer.LianZhaDealer;
import ddz.core.dealer.NoShuffleDealer;
import ddz.db.dao.TableDao;
import ddz.db.dao.UserDao;
import ddz.db.entity.ItemInfo;
import ddz.db.entity.UserInfo;
import ddz.db.service.IdGenService;
import ddz.db.service.MatchMember;
import ddz.db.service.MatchResult;
import ddz.db.service.MatcherService;
import ddz.logic.ItemUtils;
import ddz.net.ProtocolMessage;
import ddz.net.WsSender;
import ddz.numerical.manager.ConfPlaceInfoManager;
import ddz.numerical.pojo.ConfPlaceInfo;
import ddz.protos.Game;
import ddz.protos.GameFapai;
import ddz.protos.GameRecovery;
import ddz.protos.ModuleItem;
import ddz.utils.JsonUtils;
import ddz.utils.Toolkit;

import java.util.*;

@Handler(cmd = OpCode.cmd_create_desk, type = String.class)
public class CreateTableHandler extends Command implements WsSender {
    @Override
    public void execute(Message message) {
        MatchResult matchResult = (MatchResult) message.getBody();
        MatchMember[] matchMembers = matchResult.matchMembers;

        UserDao userDao = this.retrieveProxy(UserDao.class);
        TableDao tableDao = this.retrieveProxy(TableDao.class);

        Set<Long> playingUids = new HashSet<>(matchMembers.length);
        Map<Long, UserInfo> userInfoMap = new HashMap<>(matchMembers.length);
        for (int i = 0; i < matchMembers.length; i++) {
            MatchMember mm = matchMembers[i];
            if (mm.getUid() > 0 && mm.getUid() > Toolkit.maxInteger()) {
                //判断匹配的真实玩家是否仍在游戏中
                UserInfo uinfo = userDao.getUserInfo(mm.getUid());
                if (uinfo != null) {
                    userInfoMap.put(uinfo.getUid(), uinfo);
                    long deskId = uinfo.getDeskId();
                    if (deskId > 0) {
                        Table table = tableDao.getDesk(deskId);
                        if (table != null && (table.getState() == TableState.fa_pai
                                || table.getState() == TableState.jia_bei
                                || table.getState() == TableState.qiang_dizhu
                                || table.getState() == TableState.playing)) {
                            playingUids.add(mm.getUid());
                            byte[] reqBytes = GameRecovery.CsRecovery.newBuilder()
                                    .setToken("")
                                    .build().toByteArray();
                            sendMessage(new ProtocolMessage(Integer.parseInt(OpCode.cmd_recovery), reqBytes, mm.getUid()));
                        }
                    }
                }
            }
        }
        if (!playingUids.isEmpty()) {
            //有玩家正在对局中，此次匹配作废
            MatcherService matcherService = this.retrieveProxy(MatcherService.class);
            for (MatchMember mm : matchMembers) {
                if (mm.getUid() > 0 && mm.getUid() > Toolkit.maxInteger()) {
                    if (!playingUids.contains(mm.getUid())) { //其他玩家重新放入匹配池
                        matcherService.addWaitMatchPlayer(matchResult.mode, matchResult.place, mm.getUid(), mm.getScore(), mm.getParam());
                    }
                }
            }
            return;
        }

        IdGenService idGenService = this.retrieveProxy(IdGenService.class);
        Table table = new Table(idGenService.nextId(), 3);
        table.setMode(matchResult.mode);
        table.setPlace(matchResult.place);
        if (table.getMode() == GameMode.NO_SHUFFLE.getId()) {
            table.setDealer(new NoShuffleDealer(1));
        } else if (table.getMode() == GameMode.LIAN_ZHA.getId()) {
            table.setDealer(new LianZhaDealer(1));
        } else {
            if (table.getMode() == GameMode.LIAN_WIN.getId()) {
                if (table.getPlace() == GameMode.NO_SHUFFLE.getId()) {
                    table.setDealer(new NoShuffleDealer(1));
                } else if (table.getPlace() == GameMode.LIAN_ZHA.getId()) {
                    table.setDealer(new LianZhaDealer(1));
                } else {
                    table.setDealer(new Dealer(1));
                }
            } else {
                table.setDealer(new Dealer(1));
            }
        }
        ConfPlaceInfoManager confPlaceInfoManager = this.retrieveProxy(ConfPlaceInfoManager.class);
        ConfPlaceInfo confPlaceInfo = confPlaceInfoManager.getConfPlaceInfo(table.getMode(), table.getPlace());
        if (confPlaceInfo != null) {
            table.setBaseMultiple(confPlaceInfo.getMultiple());
        } else {
            table.setBaseMultiple(30);
        }
        table.setCreateTimestamp(System.currentTimeMillis());

        GameFapai.ScPlayerList.Builder playerListBuilder = GameFapai.ScPlayerList.newBuilder();

        int needRobotCount = 0; //需要机器人的数量
        for (int i = 0; i < table.getMaxPlayers(); i++) {
            MatchMember matchMember = matchMembers[i];
            if (matchMember.getUid() <= 0) needRobotCount++;
        }
        Queue<Long> robotUidQueue = null;
        if (needRobotCount > 0) {
            robotUidQueue = userDao.findRobot(needRobotCount);
        }
        for (int i = 0; i < table.getMaxPlayers(); i++) {
            long uid = -1;
            MatchMember matchMember = matchMembers[i];
            uid = matchMember.getUid();

            UserInfo userInfo;

            Player player = new Player();
            player.setReady(true);
            player.setSeatIndex(i);
            if (matchMember.params != null) {
                if (matchMember.params.containsKey("priorLookDiPai")) {
                    boolean priorLookDiPai = (boolean) matchMember.params.get("priorLookDiPai");
                    player.setPriorLookDiPai(priorLookDiPai);
                }
            }
            ModuleItem.ScUpdateItemAmount.Builder updateItemAmountBuilder = null;
            if (uid > 0 && uid > Toolkit.maxInteger()) {
                player.setUid(uid);
                player.setTimeoutCount(0);
                userInfo = userInfoMap.get(uid);
                if (userInfo == null) {
                    userInfo = createUserInfo(player.getUid(), confPlaceInfo);
                }
                updateItemAmountBuilder = ModuleItem.ScUpdateItemAmount.newBuilder();
                ModuleItem.ItemAmount.Builder itemAmountBuilder = ModuleItem.ItemAmount.newBuilder();
                if (player.isPriorLookDiPai() || table.getMode() == GameMode.LIAN_WIN.getId()) {
                    List<ItemInfo> itemInfoList = ItemUtils.parseItemList(userInfo.getItems());
                    ItemUtils.filterItems(itemInfoList);
                    if (player.isPriorLookDiPai()) {
                        ItemUtils.delItem(itemInfoList, 9, 1, userInfo); //扣除底牌卡
                        ModuleItem.ItemAmount itemAmount = itemAmountBuilder.setCid(9)
                                .setTotals(ItemUtils.getPropItemAmount(itemInfoList, 9))
                                .setChanged(1).build();
                        updateItemAmountBuilder.addItemAmount(itemAmount);
                        itemAmountBuilder.clear();
                    }
                    if (table.getMode() == GameMode.LIAN_WIN.getId() && (userInfo.getLianWin() == 0 && userInfo.getLastLianWin() == 0)) {
                        ItemUtils.delItem(itemInfoList, 6, 1, userInfo); //扣除参赛卡
                        ModuleItem.ItemAmount itemAmount = itemAmountBuilder.setCid(6)
                                .setTotals(ItemUtils.getPropItemAmount(itemInfoList, 6))
                                .setChanged(1).build();
                        updateItemAmountBuilder.addItemAmount(itemAmount);
                        itemAmountBuilder.clear();
                    }
                    userInfo.setItems(JsonUtils.toJsonString(itemInfoList));
                }
                userInfo.setGold(userInfo.getGold() - confPlaceInfo.getIntoCost());
                ModuleItem.ItemAmount itemAmount = itemAmountBuilder.setCid(1)
                        .setTotals(userInfo.getGold())
                        .setChanged(confPlaceInfo.getIntoCost()).build();
                updateItemAmountBuilder.addItemAmount(itemAmount);
                itemAmountBuilder.clear();
            } else {
                //机器人
                if (robotUidQueue != null && !robotUidQueue.isEmpty()) {
                    uid = robotUidQueue.poll();
                    userInfo = userDao.getUserInfo(uid);
                    if (table.getMode() == GameMode.LIAN_WIN.getId()) {
                        ConfPlaceInfo minPlaceInfo = confPlaceInfoManager.getConfPlaceInfo(1, 1);
                        if (minPlaceInfo != null) {
                            if (userInfo.getGold() < minPlaceInfo.getMinGold()) {
                                userInfo.setGold(minPlaceInfo.getMinGold() + MathUtils.random(1000, 3000));
                            }
                        } else {
                            userInfo.setGold(MathUtils.random(100000, 1000000));
                        }
                    } else {
                        if (confPlaceInfo != null) {
                            if (userInfo.getGold() < confPlaceInfo.getMinGold() || userInfo.getGold() > confPlaceInfo.getMaxGold()) {
                                userInfo.setGold(confPlaceInfo.getMinGold() + MathUtils.random(1000, 3000));
                            }
                        }
                    }
                } else {
                    uid = idGenService.nextId();
                    userInfo = createUserInfo(uid, confPlaceInfo);
                }
                player.setUid(uid);
                player.setTimeoutCount(TrusteeType.robot.getTimeoutCount());
            }
            userInfo.setDeskId(table.getId());
            if (table.getMode() == GameMode.LIAN_WIN.getId()) {
                userInfo.setLianWinDesk(table.getId());
            }
            userDao.insertOrUpdateUser(userInfo);
            if (updateItemAmountBuilder != null) {
                this.sendData(uid, Crypto.isCrypto, Integer.parseInt(OpCode.cmd_update_item_amount),
                        updateItemAmountBuilder.build().toByteArray());
            }

            player.setGold(userInfo.getGold());
            table.addPlayer(player);

            Game.PlayerInfo info = Game.PlayerInfo.newBuilder()
                    .setUid(userInfo.getUid())
                    .setSeat(player.getSeatIndex())
                    .setNickname(userInfo.getNickname())
                    .setHeadImg(userInfo.getHeadImg())
                    .setBeans(userInfo.getGold())
                    .setSex(userInfo.getSex())
                    .setReady(player.isReady())
                    .setMingPai(table.isMingPai(player.getSeatIndex()))
                    .setTrustee(player.getTimeoutCount() >= 2)
                    .setUsedCounter(player.isUsedCounter())
                    .setPriorLookDiPai(player.isPriorLookDiPai())
                    .build();
            playerListBuilder.addPlayer(info);
            playerListBuilder.setDeskId(table.getId());
        }
        table.setState(TableState.fa_pai);
        tableDao.insertOrUpdateDesk(table);

        int opcode = Integer.parseInt(OpCode.cmd_player_list);
        Player[] players = table.getPlayers();
        for (int i = 0; i < players.length; i++) {
            Player player = players[i];
            long uid = player.getUid();
            if (player.getTimeoutCount() != TrusteeType.robot.getTimeoutCount()) {
                this.sendData(uid, Crypto.isCrypto, opcode, playerListBuilder.build().toByteArray());
            }
        }

        this.sendMessage(new Message(OpCode.cmd_fapai, table));
    }

    private UserInfo createUserInfo(long uid, ConfPlaceInfo confPlaceInfo) {
        UserInfo userInfo = new UserInfo();
        userInfo.setMaxSeriaWin(0);
        userInfo.setSerialWin(0);
        userInfo.setWinCount(0);
        userInfo.setTotalCount(0);
        userInfo.setCreateTimestamp(System.currentTimeMillis());
        userInfo.setLastLoginTimestamp(System.currentTimeMillis());
        userInfo.setDiam(MathUtils.random(10, 100));
        userInfo.setFuka(0);
        if (confPlaceInfo != null) {
            userInfo.setGold(MathUtils.random(confPlaceInfo.getMinGold(), confPlaceInfo.getMaxGold()));
        } else {
            userInfo.setGold(MathUtils.random(100000, 1000000));
        }
        userInfo.setHeadImg(String.valueOf(MathUtils.random(0, 39)));
        userInfo.setNickname(StringUtils.randomString(6, true));
        userInfo.setScore(0);
        userInfo.setSex(MathUtils.random(1, 2));
        userInfo.setUid(uid);
        userInfo.setUnionid(StringUtils.randomString(12, false));
        userInfo.setItems("[]");
        userInfo.setToken(Tool.uuid());
        return userInfo;
    }

}
